<?php

/**
 * Clase que da acceso a funciones para configuracion
**/

/**
 *   Arreglo que contiene las consultas en cache. Estas consultas se dividen en 
 * dos tipos: Las que son globales solo para este sitio, y las que son globales
 * para todos los sitios.
 * 
 *   Este arreglo se conforma de la siguiente manera:
 * $_SESSION["QCache"]["local"][$strGNombreSitio][0]["consulta"] = "SELECT * FROM tabla"; // Consulta que se cachara
 * $_SESSION["QCache"]["local"][$strGNombreSitio][0]["timeout" ] = 60; // Tiempo de vida de los datos en segundos
 * $_SESSION["QCache"]["local"][$strGNombreSitio][0]["internal"]["data"        ] = Datos de la consulta que se estan cachando
 * $_SESSION["QCache"]["local"][$strGNombreSitio][0]["internal"]["last_timeout"] = Timestamp de la ultima vez que se obtuvieron los datos
 * 
 * $_SESSION["QCache"]["global"]["global"][0]["consulta"] = "SELECT * FROM tabla"; // Consulta que se cachara
 * $_SESSION["QCache"]["global"]["global"][0]["timeout" ] = 60; // Tiempo de vida de los datos en segundos
 * $_SESSION["QCache"]["global"]["global"][0]["internal"]["data"        ] = Datos de la consulta que se estan cachando
 * $_SESSION["QCache"]["global"]["global"][0]["internal"]["last_timeout"] = Timestamp de la ultima vez que se obtuvieron los datos
 * 
 *   Se usan dos "global" en el arreglo global para que el arreglo sea 
 * consistente en ambas partes. La variable $strGNombreSitio es seteada en el
 * archivo de configuracion del sitio
**/

/**
 * Clase de configuracion base
 */
class BaseConfig {
  /**
   * Funcion que hace un setup previo para el sistema
   * 
   * @global string $strGNombreSitio 
   * @global string $strGPath
   */
  static function Setup() {
    global $strGNombreSitio;
    global $strGPath       ;
    global $strGHost       ;
    global $strGPathP      ;
    global $strGUrlP       ;
    global $strGUploads    ;
    global $arrGMenu       ;
    
    // Primero iniciamos la sesion
    session_start();
    
    // Obtener las opciones del menu
    require_once($strGPath . "/menu_conf.inc.php");
    
    // Obtener las consultas cachadas desde inicio
    require_once($strGPath . "/cache_conf.inc.php");
    foreach($__arrGConsultasCacheConfig as $arrInfoCache) {
      if(!$arrInfoCache["consulta"]) continue;
      if(!$arrInfoCache["timeout" ]) $arrInfoCache["timeout" ] = 60;
      if(!$arrInfoCache["tipo"    ]) $arrInfoCache["tipo"    ] = "local";
      BaseConfig::CacheQuery($arrInfoCache["consulta"], $arrInfoCache["timeout"], $arrInfoCache["tipo"]);
    }
    
    // Colocar en sesion las variables del sistema. Esto se hace asi para que 
    // SWAMPY pueda accesar a dichos datos.
    // Por el momento solo se pondran los datos que SWAMPY necesita
    $_SESSION["internal_vars"] = array();
    $_SESSION["internal_vars"]["strGHost"   ] = $strGHost   ;
    $_SESSION["internal_vars"]["strGPathP"  ] = $strGPathP  ;
    $_SESSION["internal_vars"]["strGUrlP"   ] = $strGUrlP   ;
    $_SESSION["internal_vars"]["strGUploads"] = $strGUploads;
    
    
  }
  
  /**
   * Funcion que verifica si una consulta está en cache.
   * 
   * @param string $strConsulta Consulta a verificar
   * 
   * @return boolean Verdadero si la consulta es cachable, false de otra manera
   */
  static function IsCached($strConsulta) {
    global $strGNombreSitio;
    
    // La consulta se verificara en minusculas;
    $strConsulta = strtolower($strConsulta);
    
    // Primero ver las consultas locales de este sitio
    if((isset($_SESSION["QCache"])) && (isset($_SESSION["QCache"])) && (isset($_SESSION["QCache"]["local"]))) {
      foreach($_SESSION["QCache"]["local"][$strGNombreSitio] as $arrCache) {
        if($arrCache["consulta"] == $strConsulta) {
          // Si se encuentra, por lo que se regresa que si existe
          return true;
        }
      }
    }
    
    // Despues checar las consultas globales
    if((isset($_SESSION["QCache"])) && (isset($_SESSION["QCache"])) && (isset($_SESSION["QCache"]["global"]))) {
      foreach($_SESSION["QCache"]["global"]["global"] as $arrCache) {
        if($arrCache["consulta"] == $strConsulta) {
          // Si se encuentra, por lo que se regresa que si existe
          return true;
        }
      }
    }
    
    return false;
  }
  
  /**
   * Funcion que regresa el arreglo de la respuesta cachada.
   * 
   * Si la consulta está en cache, pero no hay datos de cache, se hace la 
   * consulta en este momento
   *
   * @param string $strConsulta Consulta a verificar
   * 
   * @return array Arreglo con los datos de la consulta
   */
  static function ReturnCache($strConsulta) {
    global $strGNombreSitio;
    
    // La consulta se verificara en minusculas;
    $strConsulta = strtolower($strConsulta);
    
    // Primero ver las consultas locales de este sitio
    foreach($_SESSION["QCache"]["local"][$strGNombreSitio] as $intIndice => $arrCache) {
      if($arrCache["consulta"] == $strConsulta) {
        // Aqui esta
        // Se verifica que la consulta este dentro del tiempo actual
        if(
          isset($arrCache["internal"]["last_timeout"]) && // Existe un timeout y, por tanto, datos anteriores
          ((time() - $arrCache["timeout"]) < $arrCache["internal"]["last_timeout"]) // Estamos todavia a tiempo para el timeout
        ) {
          // Entonces se regresan los datos
          return $arrCache["internal"]["data"];
        } else {
          // Se necesita hacer la consulta
          $oConecta = new Conecta();
          $oConecta->Consulta($strConsulta, true);
          $_SESSION["QCache"]["local"][$strGNombreSitio][$intIndice]["internal"]["last_timeout"] = time();
          $_SESSION["QCache"]["local"][$strGNombreSitio][$intIndice]["internal"]["data"        ] = $oConecta->GetCompleteRes();
          return $_SESSION["QCache"]["local"][$strGNombreSitio][$intIndice]["internal"]["data"];
        }
      }
    }
    
    // Despues checar las consultas globales
    foreach($_SESSION["QCache"]["global"]["global"] as $arrCache) {
      if($arrCache["consulta"] == $strConsulta) {
        // Aqui esta
        // Se verifica que la consulta este dentro del tiempo actual
        if(
          isset($arrCache["internal"]["last_timeout"]) && // Existe un timeout y, por tanto, datos anteriores
          ((time() - $arrCache["timeout"]) < $arrCache["internal"]["last_timeout"]) // Estamos todavia a tiempo para el timeout
        ) {
          // Entonces se regresan los datos
          return $arrCache["internal"]["data"];
        } else {
          // Se necesita hacer la consulta
          $oConecta = new Conecta();
          $oConecta->Consulta($strConsulta, true);
          $_SESSION["QCache"]["global"]["global"][$intIndice]["internal"]["last_timeout"] = time();
          $_SESSION["QCache"]["global"]["global"][$intIndice]["internal"]["data"        ] = $oConecta->GetCompleteRes();
          return $_SESSION["QCache"]["global"]["global"][$intIndice]["internal"]["data"];
        }
      }
    }
  }
  
  /**
   * Funcion que manda a cachar una consulta.
   * 
   * La consulta no se ejecuta en este momento, sino hasta la primera vez que sea necesitada
   * 
   * @param string $strConsulta Consulta a cachar
   * @param int    $intTimeOut  Tiempo (en segundos) que la cache es valida para esta consulta
   * @param string $strTipo     Tipo de cache (local o global)
   */
  static function CacheQuery($strConsulta, $intTimeOut = 60, $strTipo = "local") {
    global $strGNombreSitio;
    if($strTipo == "global") {
      $strSubIndice = "global";
    } else {
      $strSubIndice = $strGNombreSitio;
    }
    
    $strConsulta = strtolower($strConsulta);
    
    // Si la consulta ya existe, solo se hace un update
    foreach($_SESSION["QCache"][$strTipo][$strSubIndice] as $intIndice => $arrCache) {
      if($arrCache["consulta"] == $strConsulta) {
        // Si se encuentra, por lo que solo se actualiza
        $_SESSION["QCache"][$strTipo][$strSubIndice][$intIndice]["consulta"] = $strConsulta;
        $_SESSION["QCache"][$strTipo][$strSubIndice][$intIndice]["timeout" ] = $intTimeOut ;
        return;
      }
    }
    
    $_SESSION["QCache"][$strTipo][$strSubIndice][] = array("consulta" => $strConsulta, "timeout" => $intTimeOut);
  }
  
  /**
   * Funcion que obtiene el path real para un archivo.
   * Si no encuentra un path en los directorios datos, regresa "".
   * 
   * Regresa la ruta completa de la primer coincidencia para el archivo
   * 
   * @param string $strNombreArchivo Nombre del archivo a buscar
   * @param string $strDir1          1er Directorio en donde se buscara el archivo
   * @param string $strDir2          2o  Directorio en donde se buscara el archivo
   * @param string $strDir3          3er Directorio en donde se buscara el archivo
   * @param string $strDir4          4o  Directorio en donde se buscara el archivo
   * @param string $strDir5          4o  Directorio en donde se buscara el archivo
   * @param string $strDir6          4o  Directorio en donde se buscara el archivo
   * @param string $strDir7          4o  Directorio en donde se buscara el archivo
   * @param string $strDir8          4o  Directorio en donde se buscara el archivo
   */
  static function __ArchivoDisponible(
    $strNombreArchivo, 
    $strDir1         , 
    $strDir2 = ""    , 
    $strDir3 = ""    , 
    $strDir4 = ""    , 
    $strDir5 = ""    , 
    $strDir6 = ""    , 
    $strDir7 = ""    , 
    $strDir8 = ""      
  ) {
    if(file_exists($strDir1 . "/" . $strNombreArchivo)) { return $strDir1 . "/" . $strNombreArchivo; }
    if(file_exists($strDir2 . "/" . $strNombreArchivo)) { return $strDir2 . "/" . $strNombreArchivo; }
    if(file_exists($strDir3 . "/" . $strNombreArchivo)) { return $strDir3 . "/" . $strNombreArchivo; }
    if(file_exists($strDir4 . "/" . $strNombreArchivo)) { return $strDir4 . "/" . $strNombreArchivo; }
    if(file_exists($strDir5 . "/" . $strNombreArchivo)) { return $strDir5 . "/" . $strNombreArchivo; }
    if(file_exists($strDir6 . "/" . $strNombreArchivo)) { return $strDir6 . "/" . $strNombreArchivo; }
    if(file_exists($strDir7 . "/" . $strNombreArchivo)) { return $strDir7 . "/" . $strNombreArchivo; }
    if(file_exists($strDir8 . "/" . $strNombreArchivo)) { return $strDir8 . "/" . $strNombreArchivo; }
    
    return "";
  }
  
  /**
   * Funcion que obtiene el path real de una clase para cargar.
   * 
   * Esta funcion no realiza la llamada a require_once, porque el cuerpo del archivo
   * se incluiria en esta funcion y no en el espacio global.
   * 
   * Si el path no se encuentra, esta funcion ejecuta un backtrace
   * 
   * @global string $strGPath
   * @global string $strGBaseDirClass
   * 
   * @param  string $strNombreArchivo
   * 
   * @return string Path del archivo a cargar.
   */
  static function LoadClass($strNombreArchivo) {
    global $strGPath;
    global $strGBaseDirClass;
    
    $strArchivoCargar = BaseConfig::__ArchivoDisponible($strNombreArchivo, $strGPath . "/clases", $strGBaseDirClass);
    if($strArchivoCargar) {
      return $strArchivoCargar;
    }
    
    Variables::DebugBacktrace("No se encuentra la clase $strNombreArchivo");
  }
  
  /**
   * Funcion que obtiene la URL de un archivo extra
   * 
   * @global string $strGPath
   * @global string $strGBaseDirTop
   * 
   * @param  string $strNombreArchivo
   * @param  string $strTipo  Tipo de archivo (js, css, image, etc. Es usado en conjunto con el path para ver en que subdirectorio buscar)
   * 
   * @return string Path del archivo a cargar.
   */
  static function URLExternalRes($strNombreArchivo, $strTipo = "js") {
    global $strGPath;
    global $strGUrl ;
    global $strGBaseDirTop;
    global $strGUrlBaseSis;
    
    // Si el nombre de archivo empieza con http:// o https://, ya es una url, por lo que se regresa integra
    if((substr($strNombreArchivo, 0, 7) == "http://") || (substr($strNombreArchivo, 0, 8) == "https://")) {
      return $strNombreArchivo;
    }
    
    if(file_exists($strGPath       . "/" .$strTipo . "/" . $strNombreArchivo)) { return $strGUrl        . "/" . $strTipo . "/" . $strNombreArchivo; }
    if(file_exists($strGBaseDirTop . "/" .$strTipo . "/" . $strNombreArchivo)) { return $strGUrlBaseSis . "/" . $strTipo . "/" . $strNombreArchivo; }
    
    return "";
  }
  
  /**
   * Funcion que normaliza los path para ponerlos absolutos (Incluso en una URL)
   * 
   * @param string $strPath Path que se normalizará (Se quitaran los /./, y los /../ se regresaran un directorio
   */
  static function NormalizePath($strPath) {
    $arrPartes = explode("/", $strPath);
    $arrPartesCompleto = array();
    foreach($arrPartes as $intIndice => $strParte) {
      if($strParte == ".") {
        continue; // Se refiere al mismo directorio
      }
      $arrPartesCompleto[$intIndice] = $strParte;
      if($strParte == "..") {
        unset($arrPartesCompleto[$intIndice - 1]);
        unset($arrPartesCompleto[$intIndice - 0]);
      }
    }
    $strPathReal = join("/", $arrPartesCompleto);
    return $strPathReal;
  }
  
  /**
   * Funcion que obtiene el path real de un template
   * 
   * @global string $strGPath
   * @global string $strGBaseDirTemplates
   * 
   * @param  string $strNombreArchivo
   * 
   * @return string Path del template
   */
  static function LoadTemplate($strNombreArchivo) {
    global $strGPath;
    global $strGBaseDirTemplates;
    global $strGEstilo;
    
    $strArchivoCargar = BaseConfig::__ArchivoDisponible(
      $strNombreArchivo, 
      $strGPath . "/templates/" . $strGEstilo, 
      $strGBaseDirTemplates . "/" . $strGEstilo,
      $strGPath . "/templates", 
      $strGPath . "/templates/default", 
      $strGBaseDirTemplates
    );
    
    
    if($strArchivoCargar) {
      return $strArchivoCargar;
    }
  }
}

BaseConfig::Setup();

?>